/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package ua.yandex.prioritymap;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 *
 * @author Brothers
 */
public class MyMap<K, V> {

    final static class MyEntry<K, V> implements Map.Entry<K, V> {

        private final K key;
        private V value;

        public MyEntry(K key, V value) {
            this.key = key;
            this.value = value;
        }

        @Override
        public K getKey() {
            return key;
        }

        @Override
        public V getValue() {
            return value;
        }

        @Override
        public V setValue(V value) {
            V old = this.value;
            this.value = value;
            return old;
        }
    }

    private final int MAX = (int) Math.pow(2, 16);
    private List<List<MyEntry<K, V>>> mass;
    private int myMapSize;

    public MyMap() {
        ArrayList<List<MyEntry<K, V>>> list = new ArrayList<List<MyEntry<K, V>>>();
        for (int i = 0; i < MAX; i++) {
            list.add(new LinkedList<MyEntry<K, V>>());
        }
        this.myMapSize = 0;
        this.mass = list;
    }

    public int size() {
        return this.myMapSize;
    }

    public void sizeMinusOne() {;
        this.myMapSize--;
    }

    public boolean isEmpty() {
        return this.size() == 0;
    }

    public int myHash(K key) {
        return key.hashCode() % this.MAX;
    }

    public void put(K k, V v) {
        if (this.mass.get(myHash(k)).isEmpty()) {
            MyEntry<K, V> me = new MyEntry(k, v);
            this.mass.get(myHash(k)).add(me);
        }
        this.myMapSize++;
    }

    public boolean equals(K k, K i) {
        if (k instanceof Integer) {
            return k == i;
        } else if (k instanceof String) {
            return ((String) k).equals(i);
        }
        return false;
    }

    public V get(K k) {
        List<MyEntry<K, V>> list = this.mass.
                get(myHash(k));
        if (!this.containsKey(k)) {
            return null;
        }
        if (list.size() == 1) {
            return list.get(0).value;
        } else {
            for (MyEntry<K, V> i : list) {
                if (equals(i.key, k)) {
                    return i.value;
                }
                ;
            }
            ;
        }
        return null;
    }

    public void remove(K k) {
        List<MyEntry<K, V>> list = this.mass.get(myHash(k));
        if (list.size() > 0) {
            list.clear();
        }
        this.mass.set(myHash(k), list);
    }

    public boolean containsKey(K k) {
        return this.mass.get(myHash(k)).size() != 0;
    }

    public Set<MyEntry<K, V>> entrySet() {
        Set<MyEntry<K, V>> s = new HashSet<MyEntry<K, V>>();
        List<MyEntry<K, V>> list;
        for (int i = 0; i < this.mass.size(); i++) {
            list = this.mass.get(i);
            for (MyEntry<K, V> x : list) {
                MyEntry<K, V> e = new MyEntry(i, x.value);
                s.add(e);
            }
        }
        return s;
    }
}
